package com.plupload.servlet;

import com.plupload.model.AttributesPackage;
import com.plupload.model.TemporaryFile;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import java.io.WriteAbortedException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.SessionTrackingMode;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

/**
 * Handles the multi-part MIME encoded POST from Plupload.
 * 
 * @author Shad Aumann, JSF adaptation: Tiago Peres França
 */
public class PluploadServlet extends HttpServlet {
    static private final long serialVersionUID = 3447685998419256747L;
    static private final String RESP_SUCCESS = "{\"jsonrpc\" : \"2.0\", \"result\" : null, \"id\" : \"id\"}";
    static private final String RESP_ERROR = "{\"jsonrpc\" : \"2.0\", \"error\" : {\"code\": 101, \"message\": \"Failed to open input stream.\"}, \"id\" : \"id\"}";
    static public final String SEP = System.getProperty("file.separator");
    static public final String TMP = System.getProperty("java.io.tmpdir");
    static public final String JSON = "application/json";
    static public final int BUF_SIZE = 4096;

    // variable to reference the Plupload ManagedBean stored in session
    private AttributesPackage atts;
    

    /**
     * Handles an HTTP POST request from Plupload.
     * 
     * There's a problem with the approach used by this method, read it in
     * "com.plupload.component.SimpleQueueRenderer#encodeEnd" description.
     * 
     * @param req The HTTP request
     * @param resp The HTTP response
     * @author Shad Aumann, JSF adaptation: Tiago Peres França
     * @version 0.2
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*Set<SessionTrackingMode> tms = getServletContext().getDefaultSessionTrackingModes();
        Iterator<SessionTrackingMode> it = tms.iterator();
        while (it.hasNext()) System.out.println(it.next().getName());*/
        
        /*Enumeration<String> attsreq = req.getParameterNames();
        while (attsreq.hasMoreElements()) System.out.println(attsreq.nextElement());*/
        
        /*System.out.println(req.isRequestedSessionIdFromCookie());
        System.out.println(req.isRequestedSessionIdFromURL());
        System.out.println(req.isRequestedSessionIdValid());*/
        
        //if (req.getAttribute("Plupload") != null) System.out.println("esta na requisicao O.o");
        
        /*Enumeration<String> attsreq = getServletContext().getAttributeNames();
        System.out.println("Atts on context");
        while (attsreq.hasMoreElements()) System.out.println(attsreq.nextElement());*/
        
        HttpSession session = req.getSession(false);
        if (session == null){
            System.out.println("WARNING: plupload: session is null, getting attribute from servlet context...");
            atts = (AttributesPackage) getServletContext().getAttribute("plupload_attributes");
        }
        else{
            atts = (AttributesPackage) session.getAttribute("plupload_attributes");
            if (atts == null){
                System.out.println("WARNING: plupload: attributes are not in session, getting attribute from servlet context...");
                atts = (AttributesPackage) getServletContext().getAttribute("plupload_attributes");
            }
        }
        
        //if (atts != null) System.out.println("+++++++got it!");
        //else System.out.println("----- session exists, but plupload_attributes is not in it");
        String responseString = RESP_SUCCESS;
        boolean isMultipart = ServletFileUpload.isMultipartContent(req);

        if (isMultipart) {
            ServletFileUpload upload = new ServletFileUpload();

            try {
                FileItemIterator iter = upload.getItemIterator(req);
                while (iter.hasNext()) {
                    FileItemStream item = iter.next();
                    String name = item.getName();
                    InputStream input = item.openStream();

                    // Handle a form field.
                    if (item.isFormField()) {
                        System.out.println("name=" + name + ", value=" + Streams.asString(input));
                    }

                    // Handle a multi-part MIME encoded file.
                    else {
                        atts.getFiles().add(saveUploadFile(input, item));
                    }
                }
            }
            catch (FileUploadException e) {
                throw new IOException(e.getMessage());
            }
        }

        // Not a multi-part MIME request.
        else {
            responseString = RESP_ERROR;
        }

        resp.setContentType(JSON);
        byte[] responseBytes = responseString.getBytes();
        resp.setContentLength(responseBytes.length);
        ServletOutputStream output = resp.getOutputStream();
        output.write(responseBytes);
        output.flush();
    }

    /**
     * Saves the given file item (using the given input stream) to the web server's
     * local temp directory.
     * 
     * @param input The input stream to read the file from
     * @param item The multi-part MIME encoded file
     * @author Shad Aumann, JSF adaptation: Tiago Peres França
     * @version 0.1
     */
    private TemporaryFile saveUploadFile(InputStream input, FileItemStream item) throws IOException {
            File localFile = File.createTempFile("plupload", null);
            BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(localFile));
            byte[] data = new byte[BUF_SIZE];
            long size = 0;
            long maxSize = atts.getMaxFileSize();

            int count;
            while ((count = input.read(data, 0, BUF_SIZE)) != -1 && ((size += count) <= maxSize || maxSize == 0)) {
                    output.write(data, 0, count);
            }

            if (size > atts.getMaxFileSize() && maxSize > 0){
                input.close();
                output.close();
                localFile.delete();
                throw new WriteAbortedException("File exceeded size quota", null);
            }

            input.close();
            output.flush();
            output.close();

            TemporaryFile temp = new TemporaryFile();
            temp.setContentType(item.getContentType());
            temp.setName(item.getName());
            temp.setSize(size);
            temp.setTemporaryPath(localFile.getAbsolutePath());

            return temp;
    }
    
    /**
     * Handles the end of its servlet life. When this servlet is deleted it 
     * should also delete the Plupload Managed Bean from session. 
     * 
     * @param req The HTTP request
     * @param resp The HTTP response
     * @author Tiago Peres França
     * @version 0.1
     */
    /*@Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp){
        HttpSession session = req.getSession(false);
        if (session != null)
            session.setAttribute("plupload_attributes", null);
        getServletContext().setAttribute("plupload_attributes", null);
    }*/
}
